使用模型(X文件)

您所在的位置:网站首页 种族模型 网格 动画 使用模型(X文件)

使用模型(X文件)

2023-09-21 11:37| 来源: 网络整理| 查看: 265

在本章的前半部分,介绍了如何使用网格模型来建立地形或简单的三维图形。接下来,看看如何把三维建模软件生成的复杂三维模型导入程序中。流行的3D文件格式现在有很多种,比如.3ds、.max,.cof等,它们包含了许多信息,并且都不为像游戏引擎这样的实时环境所优化。游戏需要更快、更简单的文件格式。根据游戏类型的不同,每个游戏使用的文件格式也各不相同,比如,Quake引擎所使用的文件格式就是.md3的模型格式。

首先,看看最简单的3D文件格式.X,这是Direct3D所使用的格式,下面就研究一下.X格式的模型文件。

5.3.1 X文件格式

.X文件格式包含了两个最基本的部分:用户自定义的数据类型和层级关系。X文件是由模板(template)驱动的,模板定义了如何存储一个数据对象,这样用户便可以自己来定义具体的格式。预定义的模板位于rmxftmpl.h和rmxftmpl.x中,模板的标识符都在rmxfguid.h中,通用文件d3dfile.cpp包含了这两个头文件。模板所允许的数据类型被称为“可选成员(optional member)”,这些可选对象作为数据对象的子对象来保存。子对象可以是另一个数据对象,可以是对前一个数据对象的引用,也可以是一个二进制的对象。

X文件格式包含了下面几个主要部分。

1.首部(Header)

首部是X文件起始的部分,起始的4字节是魔数(magic number)“xof”,主版本号为03,次版本号也为03。“txt”代表文本文件格式,“bin”代表二进制文件格式。下面是一个典型的X文件的文件头:

xof 0303txt 0032

2.帧(Frame)

这个模板用来存储一个帧,帧是层次场景的构造元素。帧有它们自己的转换矩阵,还可以有自己的子对象(child objects)。帧也可以有子帧。在skin meshes中,骨骼(bone)指的就是一个帧。

3.变换矩阵(FrameTransformMatrix)

正所谓人如其名,这个变换矩阵是帧的变换。它在Frame模板里有实例。下面的文件片断描述一个帧chr_h_047,该帧带有一个子帧,有一个mesh格式的子对象:

Frame chr_h_047 {

   FrameTransformMatrix {

1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,

0.000000,0.000000,1.000000,0.000000,0.000000,-0.323429,-35.371239,

1.476196,1.000000;;

}

Frame {

   FrameTransformMatrix {

1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,

0.000000,0.000000,0.000000,1.000000,0.000000,0.016750,0.671672,

-31.375168,1.000000;;

   }

   Mesh {

    }

4.网格模型(Mesh)

这个模板存储一个表态的mesh和mesh的材质。在skin meshes里,整个角色将只是一个mesh,由皮肤信息(skinning information)确定mesh中的每一个部分是如何受到骨骼的影响的。mesh在内部会分成几个子集,每一个子集将受到一个特定的骨骼集合的影响。

5.XskinMeshHeader

这个模板存储随mesh一起导出的(exported)关于皮肤信息的属性(nature)。这个模板包含在mesh模板里面。

template XSkinMeshHeader {

WORD nMaxSkinWeightsPerVertex;

WORD nMaxSkinWeightsPerFace;

WORD nBones;

}

6.SkinWeights

真正的皮肤信息就存储在这里,这个模板定义了一个特定的骨骼能够去影响一个mesh。这个模板在每一个影响到mesh的骨骼里面都有实例。例如,有12个骨骼影响到mesh,mesh模板里将有12个SkinWeights模板的实例。

template SkinWeights {

STRING transformNodeName;

DWORD nWeights;

array DWORD vertexIndices[nWeights];

array FLOAT weights[nWeights];

Matrix4x4 matrixOffset;

}

如果建立的是带有骨骼动画的模型,它和静态模型最大的区别就在于骨骼动画模型必须有XskinMeshHeader和SkinWeights模板。如果把这两个模板从任何一个skin mesh里面移走的话,就会得到一个静态的mesh(static mesh)。

7.VertexDuplicationIndices

模型的索引缓冲区格式:

template VertexDuplicationIndices {

DWORD nIndices;

DWORD nOriginalVertices;

array DWORD indices[nIndices];

}

8.材质和纹理

模型的材质和纹理信息都包含在Mesh中,可以直接从X文件里读取材质和纹理信息。纹理是以文件的形式存储的:

Material {

1.000000;1.000000;1.000000;1.000000;;

0.000000;

1.000000;1.000000;1.000000;;

0.000000;0.000000;0.000000;;

TextureFilename {

   ".//chr_h_047.bmp";

}

}

9.动画

在X文件里包含了一个动画集(AnimationSet),每个动画集里的动画都属于对某个框架的引用。例如:下面的X文件动画集就分别是对帧Scene_Root和chr_h_047的引用:

AnimationSet {

Animation {

   AnimationKey {

   4;

   2;

…0;16;1.000000,0.000000,0.000000,0.000000,0.000000,1.000000, 0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000;;,

     }

{ Scene_Root }

}

Animation {

    AnimationKey {

   4;

   2;

…   16160;16;1.000000,0.000000,0.000000,0.000000,0.000000,0.000000, -1.000000,0.000000,0.000000,1.000000,0.000000,0.000000,-0.323429,-35.371239,1.476196,1.000000;;;

}

{ chr_h_047 }

}

}

5.3.2 输出.X文件格式

可以有多种方法来得到X文件。首先需要使用三维建模软件来建立需要的三维模型,如3DS Max、MAYA。接着,可以使用三维建模软件的插件来导出X文件。

可以使用的导出插件包括XSkinExp、Panda等,从实用角度看,Panda更胜一筹。无论是导出静态模型,还是导出带有骨骼动画的动态模型,一般都不会出问题。这个插件可从下面这个网址下载:http://www.andytather.co.uk /Panda/directxmax_downloads.aspx。

Panda针对不同的3DSM ax版本,有不同版本的插件与之对应,在使用时只要把PandaDXExport*.dle(*对应的是版本)这个文件放在3DS Mas安装目录下的plugins目录中就可以了,3DS Mas在启动后会自动识别这个插件。

在3DS Max中打开一个模型,并单击“输出”按钮后,弹出如图5-10所示的保存对话框,选择Panda对应的保存格式,并单击“打开”按扭。在弹出的保存选项对话框中按图5-11~图5-14的指示进行选择即可。

图5-10 Panda插件的保存类型

图5-11 对象参数

图5-12 动画参数

图5-13 纹理的设置

图5-14 X文件格式的设置

经过一系列正确设置后,就会导出一个相应的X文件。同时这个X文件中用到的位图文件也会一并导出。输出文件后,应该检查一下文件内容对不对,这个时候可以用DirectX中自带的观看模型工具Mesh Viewer来看,如图5-15所示。

图5-15 用Mesh Viewer工具查看导出的模型

5.3.3 在Direct3D程序中载入X文件

在Direct3D中,3D模型都是以网格模型的形式使用的,它将数据从X文件中读出,通过函数D3DCreateMesh()来创建3D图形。不过通常情况下不用显式地调用函数D3DcreateMesh(),它已经被封装在其他Direct3D功能扩展库函数中。

1.从文件中读取网格模型

函数D3DXLoadMeshFromX()用于从X文件中提取多边形网格信息(包括顶点坐标、颜色、法线向量、纹理信息等),生成多边形网格。函数声明如下:

HRESULT D3DXLoadMeshFromX(        

    LPCTSTR pFilename,                   //X文件路径和文件名

    DWORD Options,                       //指定生成多边形网格属性

    LPDIRECT3DDEVICE9 pDevice,           //Direct3D设备指针

    LPD3DXBUFFER* ppAdjacency,           //存储临近多边形信息的内存地址

    LPD3DXBUFFER* ppMaterials,           //存储材质的内存地址

    LPD3DXBUFFER* ppEffectInstances, //存储模型特殊效果的内存地址

    DWORD* pNumMaterials,                //存储材质数目的内存地址

    LPD3DXMESH* ppMesh                   //存储生成的多边形网格的内存地址

);

其中,LPD3DXBUFFER可以存储如顶点缓冲区、材质、纹理等多种类型的Direct3D数据,而不必对每一种数据声明一个函数接口类型。

下面的函数片断从名为“game”的X文件里读取3D模型:

if( FAILED( D3DXLoadMeshFromX( "game.x", D3DXMESH_SYSTEMMEM,

        g_pd3dDevice, NULL, &pD3DXMtrlBuffer,NULL,

        &g_dwNumMaterials, &g_pMesh ) ) )

{

    return E_FAIL;

}

2.载入纹理和材质

函数D3DXLoadMeshFromX()调用成功后,参数pNumMaterials就会获得 X文件中三维模型的材质和纹理信息,而pNumMaterials会存储材质的数目。

下面的程序片断用于获取3D模型的材质和纹理信息。

【例5-5】得到模型中的材质和纹理信息:

// 从材质集合中把材质和纹理信息解压读取出来

D3DXMATERIAL* d3dxMaterials =

                (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();

g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];

g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];

for( DWORD i=0; i

        g_pMeshTextures[i] = NULL;

    }

}

// 释放材质缓冲区的内容

pD3DXMtrlBuffer->Release();

3.绘制网格模型

最后,调用函数DrawSubset()绘制多边形网格的3D模型,如图5-12所示。

// 用循环绘制每一个网格面。

for( DWORD i=0; i



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3